﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Data;
using System.Reflection;
using Sparkle.Lib;
using System.ComponentModel.DataAnnotations;
using Sparkle.Lib.Attributes;
using Sparkle.Lib.Utility;

namespace Sparkle.UI
{
    public class Metadata : IValueConverter, IClientValidate
    {
        #region private variables

        ValidationAttribute[] validationList = null;

        PropertyInfo _pInfo = null;

        #endregion

        #region Constructors

        //object _entity = null;
        //public Metadata(PropertyInfo pInfo, object entity)
        public Metadata(PropertyInfo pInfo)
        {
            _pInfo = pInfo;
            // _entity = entity;
            _name = pInfo.Name;
            _title = _name;
            _type = pInfo.PropertyType;
            _readOnly = !_pInfo.CanWrite;

            getUIAtributes();
        }

        #endregion

        #region attributes

        public string FullName 
        {
            get 
            {
                if (_pInfo.DeclaringType != null)
                {
                    return string.Format("{0}.{1}", _pInfo.DeclaringType.FullName, this._name);
                }
                return this._name;
            } 
        }

        private string _name = string.Empty;

        public string Name
        {
            get { return _name; }
            // set { _name = value; }
        }

        private string _title = string.Empty;

        /// <summary>
        /// Set Title of UI
        /// </summary>
        public string Title
        {
            get { return _title; }
            set { _title = value; }
        }

        private Type _type = null;

        public Type MetaType
        {
            get { return _type; }
            //set { _type = value; }
        }

        private bool _readOnly = false;

        /// <summary>
        /// set readonly
        /// </summary>
        public bool ReadOnly
        {
            get { return _readOnly; }
            set { _readOnly = value; }
        }

        private bool _enable = true;

        /// <summary>
        /// set enable
        /// </summary>
        public bool Enable
        {
            get { return _enable; }
            set { _enable = value; }
        }

        private bool _visible = true;

        /// <summary>
        /// set Visible
        /// </summary>
        public bool Visible
        {
            get { return _visible; }
            set { _visible = value; }
        }

        private int _order = 0;

        /// <summary>
        /// set Index
        /// </summary>
        public int Order
        {
            get { return _order; }
            set { _order = value; }
        }

        #region LableAt

        private LabelLocation _labelAt = LabelLocation.Left;
        /// <summary>
        /// LableAt
        /// </summary>
        public LabelLocation LableAt
        {
            get { return _labelAt; }
            set { _labelAt = value; }
        }

        #endregion LableAt

        ////////////////
        #region UILocation Attributes

        VisualizationAttribute _visualization = null;

        public VisualizationAttribute Visualization
        {
            get { return _visualization; }
        }

        #endregion

        private string _group = string.Empty;


        public string Group
        {
            get { return _group; }
        }


        #region Description
        private string _description = string.Empty;
        /// <summary>
        /// Description
        /// </summary>
        public string Description
        {
            get { return _description; }
            set { _description = value; }
        }

        #endregion Description



        #region NotifyOnValidationError
        private bool _notifyOnValidationError = false;
        /// <summary>
        /// EnableInvalidValueValidation
        /// </summary>
        public bool NotifyOnValidationError
        {
            get { return _notifyOnValidationError; }
            set { _notifyOnValidationError = value; }
        }

        #endregion NotifyOnValidationError


        #endregion

        #region Private methods

        /// <summary>
        /// Get and set Ui Atrributes
        /// </summary>
        private void getUIAtributes()
        {
            DisplayAttribute display = new DisplayAttribute();
            if (CustomAttribute.HasAttribute<DisplayAttribute>(_pInfo, out display))
            {
                _title = display.GetName();
                _group = display.GetGroupName();
                _description = display.GetDescription();
                _order = display.Order;
            }

            if (CustomAttribute.HasAttribute<VisualizationAttribute>(_pInfo, out _visualization))
            {
                _readOnly = _visualization.ReadOnly;
                _visible = _visualization.Visible;
                _enable = _visualization.Enable;
                _labelAt = _visualization.LableAt;
            }
        }



        #endregion

        #region public methods

        #region Validations

        public void GetValidationRules()
        {
            if (!CustomAttribute.HasAttributes<ValidationAttribute>(_pInfo, out validationList))
            {
                validationList = null;
            }
        }
        #endregion

        public override string ToString()
        {
            return string.Format("Name={0} Title={1} Type={2}", this.Name, this.Title, this.MetaType);
        }

        #region get and  set the value

        public object GetValue(object entity)
        {
            return _pInfo.GetValue(entity, null);
        }

        public void SetValue(object entity, object value)
        {
            _pInfo.SetValue(entity, value, null);
        }

        #endregion


        public bool Validate(object value)
        {
            if (validationList == null || _clientValidate == null)
                return true;

            bool retVal = true;
            string errorMessage = string.Empty;
#if SILVERLIGHT
            ValidationContext validationContext = new ValidationContext(this, null, null);
            validationContext.DisplayName = this.Title ?? this.Name;
#endif

            foreach (var item in validationList)
            {
                try
                {
#if SILVERLIGHT

                    item.Validate(value, validationContext);

                    retVal = retVal ? true : false;
#else

                    item.Validate(value, this.Title ?? this.Name);
#endif
                    retVal = retVal ? true : false;
                }
                catch (ValidationException vex)
                {
                    errorMessage = vex.Message;
                    retVal = false;
                    break;
                }
            }

            _clientValidate(retVal, errorMessage);

            return retVal;
        }

        #endregion

        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value == null)
                return value;

            ValueConverter valueConverter = null;
            Type registerdType = value.GetType();
            if (!UIDefaults.IsRegisterdValueConverter(registerdType))
            {
                if (UIDefaults.IsRegisterdValueConverter(registerdType.BaseType))
                {
                    valueConverter = UIDefaults.ValueConverters[registerdType.BaseType];
                }

            }
            else
            {
                valueConverter = UIDefaults.ValueConverters[registerdType];
            }

            if (valueConverter != null && valueConverter.ConvertTo != null)
            {
                try
                {
                    return valueConverter.ConvertTo(value, targetType);
                }
                catch (Exception ex)
                {
                    return value;
                }

            }
            else
            {
                return value;
            }

            //return System.Convert.ChangeType(value, targetType, null);
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            object retVal = value;

            if (value == null)
                goto Finish;

            ValueConverter valueConverter = null;

            Type registerdType = targetType;

            if (!UIDefaults.IsRegisterdValueConverter(registerdType))
            {
                if (UIDefaults.IsRegisterdValueConverter(registerdType.BaseType))
                {
                    valueConverter = UIDefaults.ValueConverters[registerdType.BaseType];
                }

            }
            else
            {
                valueConverter = UIDefaults.ValueConverters[registerdType];
            }


            if (valueConverter != null && valueConverter.ConvertBack != null)
            {
                try
                {
                    retVal = valueConverter.ConvertBack(value, targetType);
                    if (NotifyOnValidationError && _clientValidate != null)
                    {
                        _clientValidate(true, "");
                    }
                }
                catch (Exception ex)
                {
                    if (NotifyOnValidationError && _clientValidate != null)
                    {
                        _clientValidate(false, ex.Message);
                    }
                }
            }

        Finish:
            bool isValid = Validate(retVal);
            return retVal;
        }

        #endregion

        #region IClientValidate Members

        ClientValidateDelegate _clientValidate = null;

        public ClientValidateDelegate ClientValidate
        {
            get { return _clientValidate; }
            set { _clientValidate = value; }
        }

        #endregion
    }

}
